package com.tsfyun.scm.service.impl.order;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Snowflake;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.enums.domain.DomainOprationEnum;
import com.tsfyun.common.base.enums.domain.MaterielStatusEnum;
import com.tsfyun.common.base.enums.exp.CollectionSourceEnum;
import com.tsfyun.common.base.enums.exp.ExpSettlementModeEnum;
import com.tsfyun.common.base.enums.finance.CostClassifyEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.support.DomainStatus;
import com.tsfyun.common.base.util.LocalDateTimeUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.base.DataCalling;
import com.tsfyun.scm.dto.order.ExpOrderCostQTO;
import com.tsfyun.scm.entity.customer.ExpAgreement;
import com.tsfyun.scm.entity.order.ExpOrder;
import com.tsfyun.scm.entity.order.ExpOrderCost;
import com.tsfyun.scm.entity.order.ExpOrderMember;
import com.tsfyun.scm.mapper.order.ExpOrderCostMapper;
import com.tsfyun.scm.service.base.ICurrencyService;
import com.tsfyun.scm.service.customer.IExpAgreementService;
import com.tsfyun.scm.service.order.IExpOrderCostService;
import com.tsfyun.scm.service.order.IExpOrderMemberService;
import com.tsfyun.scm.service.order.IExpOrderService;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.base.CurrencyVO;
import com.tsfyun.scm.vo.order.ExpOrderCostVO;
import com.tsfyun.scm.vo.order.ExpOrderMemberVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ExpOrderCostServiceImpl extends ServiceImpl<ExpOrderCost> implements IExpOrderCostService {

    @Autowired
    private IExpOrderService expOrderService;
    @Autowired
    private IExpAgreementService expAgreementService;
    @Autowired
    private IExpOrderMemberService expOrderMemberService;
    @Autowired
    private ExpOrderCostMapper expOrderCostMapper;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private ICurrencyService currencyService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculationCost(ExpOrder expOrder) {
        calculationCost(expOrder, LocalDateTimeUtils.convertLocalDate());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculationCost(ExpOrder expOrder, LocalDateTime orderDate) {
        expOrder.setOrderDate(orderDate);
        //获取海关汇率
        BigDecimal customsRate = DataCalling.getInstance().obtainCustomsRate(expOrder.getCurrencyId(),expOrder.getOrderDate());
        TsfPreconditions.checkArgument(Objects.nonNull(customsRate),new ServiceException("未取到有效海关汇率请稍后重试"));
        expOrder.setCustomsRate(customsRate);//写入海关汇率
        //计算转美金汇率
        if("USD".equals(expOrder.getCurrencyId())){
            expOrder.setUsdRate(BigDecimal.ONE);//美金转换汇率
        }else{
            BigDecimal CNYRate = BigDecimal.ONE;//人民币汇率
            if(!"CNY".equals(expOrder.getCurrencyId())){
                CNYRate = expOrder.getCustomsRate();
            }
            expOrder.setUsdRate(CNYRate.divide(DataCalling.getInstance().obtainCustomsRate("USD",expOrder.getOrderDate()),8,BigDecimal.ROUND_HALF_UP));
        }
        //获取协议报价
        ExpAgreement agreement = expAgreementService.getById(expOrder.getAgreementId());
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("当前客户协议报价已经被作废删除，请退回重新选择"));
        agreement = expAgreementService.validationAgreement(expOrder.getAgreementId());
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("当前客户协议报价已经失效，请退回重新选择"));
        //获取包含归类物料的产品信息
        List<ExpOrderMemberVO> expOrderMemberVOS = expOrderMemberService.findOrderMaterielMember(expOrder.getId());
        //更新的订单明细
        List<ExpOrderMember> updateMemberList = Lists.newArrayList();
        for(ExpOrderMemberVO vo : expOrderMemberVOS){
            //物料未归类
            if (!Objects.equals(MaterielStatusEnum.of(vo.getMaterielStatusId()), MaterielStatusEnum.CLASSED)) {
                throw new ServiceException(String.format("第【%d】行：【%s】【%s】【%s】还未完成归类", vo.getRowNo(), vo.getName(),vo.getBrand(),vo.getModel()));
            }
            //同步产品信息
            ExpOrderMember eom = new ExpOrderMember();
            eom.setId(vo.getId());
            eom.setName(vo.getDecName());
            eom.setBrand(vo.getDecBrand());
            eom.setSpec(vo.getSpec());
            //加入修改明细
            updateMemberList.add(eom);
        }
        List<ExpOrderCost> costList = Lists.newArrayList();
        // 计算代理费
        BigDecimal serviceVal;
        switch (ExpSettlementModeEnum.of(agreement.getSettlementMode())){
            case ONE_DOLLAR:// 每1美金收取人民币
                serviceVal = expOrder.getTotalPrice().multiply(expOrder.getUsdRate()).multiply(agreement.getAgencyFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
                break;
            case DECLARE_TOTAL_PERCENT:// 按报关总价百分比
                serviceVal = expOrder.getTotalPrice().multiply(expOrder.getCustomsRate()).multiply(agreement.getAgencyFee()).divide(BigDecimal.valueOf(100),2,BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP);
                break;
            default:
                throw new ServiceException("代理费计算模式错误");
        }
        //最低消费
        if(serviceVal.compareTo(agreement.getMinAgencyFee())==-1){
            serviceVal = agreement.getMinAgencyFee();
        }
        ExpOrderCost cost = new ExpOrderCost();
        cost.setExpenseSubjectId("A0001");//科目
        cost.setCostClassify(CostClassifyEnum.DZF.getCode());//分类
        cost.setCollectionSource(CollectionSourceEnum.DEDUCTION.getCode());//支付方式
        cost.setActualAmount(serviceVal);//原始金额
        cost.setReceAmount(serviceVal);//应收金额
        cost.setIsAutomatic(Boolean.TRUE);//系统生成
        cost.setOperator("系统");
        cost.setIsAllowEdit(Boolean.TRUE);//允许修改
        costList.add(cost);

        //保存生成的费用
        List<ExpOrderCost> saveCostList = Lists.newArrayList();
        // 删除原始系统生成的费用明细
        removeAutomaticOrderId(expOrder.getId());
        //根据订单获取非系统生成的杂费费用信息
        List<ExpOrderCost> dzfOrderCosts = expOrderCostMapper.findByNonAutomaticZfList(expOrder.getId());
        List<String> expenseSubjectIds = dzfOrderCosts.stream().map(ExpOrderCost::getExpenseSubjectId).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(costList)){
            costList.stream().forEach(co ->{
                //费用未被人工调整
                if(!expenseSubjectIds.contains(co.getExpenseSubjectId())){
                    co.setId(snowflake.nextId());
                    co.setExpOrderId(expOrder.getId());
                    co.setAcceAmount(BigDecimal.ZERO);
                    co.setIsFirstWriteOff(Boolean.FALSE);
                    co.setIsLock(Boolean.FALSE);
                    co.setHappenDate(expOrder.getOrderDate());
                    co.setPeriodDate(expOrder.getOrderDate());
                    co.setLateFeeDate(expOrder.getOrderDate());
                    co.setOverdueRate(BigDecimal.ZERO);
                    saveCostList.add(co);
                }
            });
        }
        if(CollUtil.isNotEmpty(saveCostList)){
            //批量保存
            savaBatch(saveCostList);
        }
        //更新订单明细
        expOrderMemberService.batchUpdatePartData(updateMemberList);
        //更新订单主单
        expOrderService.updateById(expOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAutomaticOrderId(Long orderId) {
        try{
            ExpOrderCost delete = new ExpOrderCost();
            delete.setExpOrderId(orderId);//订单
            delete.setIsAutomatic(Boolean.TRUE);//系统生成
            super.remove(delete);
        }catch (Exception e){
            throw new ServiceException("系统费用已被核销，请检查");
        }
    }

    @Override
    public List<ExpOrderCostVO> checkGetAdjustCost(String expOrderNo, Boolean getCost) {
        ExpOrder order = expOrderService.findByDocNo(expOrderNo);
        Optional.ofNullable(order).orElseThrow(()->new ServiceException("订单号错误"));
        //审核通过的订单
        DomainStatus.getInstance().check(DomainOprationEnum.EXP_ORDER_ADJUST_COST,order.getStatusId());
        if(Objects.equals(getCost,Boolean.TRUE)) {
            return getAllCosts(order.getId(), null);
        }
        return Lists.newArrayList();
    }

    @Override
    public List<ExpOrderCostVO> getAllCosts(Long orderId, String expOrderNo) {
        if(Objects.isNull(orderId) && StringUtils.isEmpty(expOrderNo)) {
            throw new ServiceException("订单id和订单号不能同时为空");
        }
        List<ExpOrderCostVO> list = expOrderCostMapper.getAllOrderCosts(orderId,expOrderNo);
        if(CollUtil.isNotEmpty(list)) {
            return list.stream().sorted(Comparator.comparing(ExpOrderCostVO::getExpenseSubjectId)).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public List<ExpOrderCostVO> findCostByOrderIdAndCollectionSource(Long orderId, List<String> collectionSources) {
        List<ExpOrderCostVO> list = expOrderCostMapper.findCostByOrderIdAndCollectionSource(orderId,collectionSources);
        if(CollUtil.isNotEmpty(list)) {
            return list.stream().sorted(Comparator.comparing(ExpOrderCostVO::getExpenseSubjectId)).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public List<ExpOrderCost> getByExpenseSubject(Long orderId, String expenseSubjectId) {
        ExpOrderCost condition = new ExpOrderCost();
        condition.setExpOrderId(orderId);
        condition.setExpenseSubjectId(expenseSubjectId);
        return super.list(condition);
    }

    @Override
    public ExpOrderCostVO getSimpleCostInfo(Long expOrderCostId) {
        ExpOrderCost expOrderCost = super.getById(expOrderCostId);
        Optional.ofNullable(expOrderCost).orElseThrow(()->new ServiceException("订单费用信息不存在"));
        return beanMapper.map(expOrderCost,ExpOrderCostVO.class);
    }

    @Override
    public void removeByOrderId(Long orderId) {
        expOrderCostMapper.deleteByExample(Example.builder(ExpOrderCost.class)
                .where(TsfWeekendSqls.<ExpOrderCost>custom()
                        .andEqualTo(false,ExpOrderCost::getExpOrderId,orderId)).build());
    }

    @Override
    public List<ExpOrderCostVO> canWriteOffByOrderId(Long orderId) {
        return expOrderCostMapper.canWriteOffByOrderId(orderId);
    }

    @Override
    public List<ExpOrderCostVO> canWriteOffList(Long customerId) {
        return expOrderCostMapper.canWriteOffList(customerId);
    }

    @Override
    public BigDecimal obtainOrderAdvancePayment(Long orderId, String collectionSource) {
        return expOrderCostMapper.obtainOrderAdvancePayment(orderId,collectionSource);
    }

    @Override
    public void expLockCost(Long orderId) {
        expOrderCostMapper.expLockCost(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void purchaseInvoiceCompleted(Long orderId) {
        // 订单采购合同收票完成将订单税款扣除类型置位已收款
        expOrderCostMapper.updateCollectionCompletedByOrder(orderId,CollectionSourceEnum.DEDUCTION.getCode());
    }

    @Override
    public List<ExpOrderCostVO> obtainOrderNotLockCosts(Long orderId) {
        return expOrderCostMapper.obtainOrderNotLockCosts(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void expUnLockCost(List<Long> costIds) {
        if(CollUtil.isEmpty(costIds)){
            return;
        }
        expOrderCostMapper.expUnLockCost(costIds);
    }

    @Override
    public ExpOrderCost findByExpOrderNoAndExpenseSubjectId(String expOrderNo, String expenseSubjectId) {
        return expOrderCostMapper.findByExpOrderNoAndExpenseSubjectId(expOrderNo,expenseSubjectId);
    }

    @Override
    public List<ExpOrderCost> findByExpOrderNoBatch(List<String> expOrderNos) {
        if(CollUtil.isEmpty(expOrderNos)) {
            return null;
        }
        return expOrderCostMapper.findByExpOrderNoBatch(expOrderNos);
    }

    @Override
    public PageInfo<ExpOrderCostVO> pageList(ExpOrderCostQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        Map<String,Object> params = beanMapper.map(qto,Map.class);
        List<ExpOrderCostVO> dataList = expOrderCostMapper.list(params);
        if(CollUtil.isNotEmpty(dataList)) {
            Map<String,CurrencyVO> currencyMap = currencyService.select().stream().collect(Collectors.toMap(CurrencyVO::getId, Function.identity()));
            dataList.stream().forEach(data->{
                data.setPayCurrencyName(Optional.ofNullable(currencyMap.get(data.getPayCurrencyCode())).map(CurrencyVO::getName).orElse(""));
            });
        }
        return new PageInfo<>(dataList);
    }
}
